package com.yuanqi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuanqi.mapper.SalesOrderAttachmentMapper;
import com.yuanqi.pojo.SalesOrderAttachment;
import com.yuanqi.dto.SalesOrderAttachmentDTO;
import com.yuanqi.service.SalesOrderAttachmentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.annotation.PostConstruct;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 销售订单附件服务实现类
 */
@Service
public class SalesOrderAttachmentServiceImpl extends ServiceImpl<SalesOrderAttachmentMapper, SalesOrderAttachment> 
        implements SalesOrderAttachmentService {
    
    @Value("${file.upload.path:${user.home}/yuanqi-uploads}")
    private String uploadPath;
    
    @Value("${file.max.size:10485760}")
    private long maxFileSize;
    
    // 允许的文件类型
    private static final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
        "pdf", "doc", "docx", "xls", "xlsx", "jpg", "jpeg", "png", "gif", "zip", "rar", "txt"
    );
    
    @PostConstruct
    public void init() {
        // 确保上传路径存在
        try {
            File uploadDir = new File(uploadPath);
            if (!uploadDir.exists()) {
                boolean created = uploadDir.mkdirs();
                if (created) {
                    System.out.println("=== 附件服务初始化成功 ===");
                    System.out.println("上传路径: " + uploadPath);
                    System.out.println("最大文件大小: " + maxFileSize + " bytes (" + (maxFileSize / 1024 / 1024) + " MB)");
                } else {
                    System.err.println("=== 附件服务初始化失败 ===");
                    System.err.println("无法创建上传目录: " + uploadPath);
                }
            } else {
                System.out.println("=== 附件服务初始化成功 ===");
                System.out.println("上传路径已存在: " + uploadPath);
                System.out.println("最大文件大小: " + maxFileSize + " bytes (" + (maxFileSize / 1024 / 1024) + " MB)");
            }
        } catch (Exception e) {
            System.err.println("=== 附件服务初始化异常 ===");
            System.err.println("初始化失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    @Override
    public SalesOrderAttachmentDTO uploadAttachment(Long soId, MultipartFile file, String description, String uploader) throws IOException {
        System.out.println("=== 单个文件上传开始 ===");
        System.out.println("文件信息: " + (file != null ? file.getOriginalFilename() + " (" + file.getSize() + " bytes)" : "null"));
        
        // 验证文件
        validateFile(file);
        System.out.println("文件验证通过");
        
        // 生成文件名和路径
        String originalFilename = file.getOriginalFilename();
        String extension = getFileExtension(originalFilename);
        String fileName = generateFileName(originalFilename);
        String filePath = uploadPath + File.separator + fileName;
        
        System.out.println("原始上传路径配置: " + uploadPath);
        System.out.println("系统分隔符: " + File.separator);
        System.out.println("生成的文件名: " + fileName);
        System.out.println("完整文件路径: " + filePath);
        System.out.println("当前工作目录: " + System.getProperty("user.dir"));
        System.out.println("用户主目录: " + System.getProperty("user.home"));
        
        // 创建目录 - 确保路径存在
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            boolean created = uploadDir.mkdirs();
            if (created) {
                System.out.println("创建上传目录成功: " + uploadPath);
            } else {
                System.out.println("创建上传目录失败: " + uploadPath);
                throw new RuntimeException("无法创建上传目录: " + uploadPath);
            }
        } else {
            System.out.println("上传目录已存在: " + uploadPath);
        }
        
        // 保存文件
        File destFile = new File(filePath);
        file.transferTo(destFile);
        System.out.println("文件保存成功: " + destFile.getAbsolutePath());
        
        // 创建附件记录
        SalesOrderAttachment attachment = new SalesOrderAttachment();
        attachment.setSoId(soId);
        attachment.setAttachmentName(originalFilename);
        attachment.setAttachmentType(determineAttachmentType(extension));
        attachment.setFileSize(file.getSize());
        attachment.setFilePath(filePath);
        attachment.setFileUrl("/api/sales/attachment/download/" + fileName);
        attachment.setUploader(uploader);
        attachment.setUploadTime(new Date());
        attachment.setDescription(description);
        attachment.setStatus(1);
        attachment.setCreatedAt(new Date());
        attachment.setUpdatedAt(new Date());
        
        System.out.println("附件记录创建完成，准备保存到数据库");
        
        // 保存到数据库
        save(attachment);
        System.out.println("附件记录保存到数据库成功，ID: " + attachment.getId());
        
        System.out.println("=== 单个文件上传结束 ===");
        return convertToDTO(attachment);
    }
    
    @Override
    public List<SalesOrderAttachmentDTO> uploadAttachments(Long soId, MultipartFile[] files, String description, String uploader) throws IOException {
        List<SalesOrderAttachmentDTO> results = new ArrayList<>();
        
        System.out.println("=== 服务层批量上传开始 ===");
        System.out.println("接收到的文件数量: " + (files != null ? files.length : "null"));
        
        if (files == null || files.length == 0) {
            System.out.println("警告：文件数组为空或null");
            return results;
        }
        
        for (int i = 0; i < files.length; i++) {
            MultipartFile file = files[i];
            System.out.println("处理文件 " + (i + 1) + ": " + 
                (file != null ? file.getOriginalFilename() + " (" + file.getSize() + " bytes)" : "null"));
            
            try {
                if (file != null && !file.isEmpty()) {
                    SalesOrderAttachmentDTO dto = uploadAttachment(soId, file, description, uploader);
                    results.add(dto);
                    System.out.println("文件 " + (i + 1) + " 上传成功");
                } else {
                    System.out.println("文件 " + (i + 1) + " 为空或空文件，跳过");
                }
            } catch (Exception e) {
                System.out.println("文件 " + (i + 1) + " 上传失败: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        System.out.println("=== 服务层批量上传结束，成功数量: " + results.size() + " ===");
        return results;
    }
    
    @Override
    public void downloadAttachment(Long attachmentId, HttpServletResponse response) throws IOException {
        SalesOrderAttachment attachment = getById(attachmentId);
        if (attachment == null) {
            throw new RuntimeException("附件不存在");
        }
        
        File file = new File(attachment.getFilePath());
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }
        
        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + 
            URLEncoder.encode(attachment.getAttachmentName(), StandardCharsets.UTF_8.name()));
        
        // 写入文件流
        try (FileInputStream fis = new FileInputStream(file);
             OutputStream os = response.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
            os.flush();
        }
    }
    
    @Override
    public void downloadAttachmentsAsZip(List<Long> attachmentIds, HttpServletResponse response) throws IOException {
        List<SalesOrderAttachment> attachments = listByIds(attachmentIds);
        if (attachments.isEmpty()) {
            throw new RuntimeException("没有找到附件");
        }
        
        // 设置响应头
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=attachments.zip");
        
        // 创建ZIP文件
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            for (SalesOrderAttachment attachment : attachments) {
                File file = new File(attachment.getFilePath());
                if (file.exists()) {
                    ZipEntry entry = new ZipEntry(attachment.getAttachmentName());
                    zos.putNextEntry(entry);
                    
                    try (FileInputStream fis = new FileInputStream(file)) {
                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = fis.read(buffer)) > 0) {
                            zos.write(buffer, 0, length);
                        }
                    }
                    zos.closeEntry();
                }
            }
        }
    }
    
    @Override
    public boolean deleteAttachment(Long attachmentId) {
        SalesOrderAttachment attachment = getById(attachmentId);
        if (attachment == null) {
            return false;
        }
        
        // 删除物理文件
        File file = new File(attachment.getFilePath());
        if (file.exists()) {
            file.delete();
        }
        
        // 逻辑删除数据库记录
        attachment.setStatus(0);
        attachment.setUpdatedAt(new Date());
        return updateById(attachment);
    }
    
    @Override
    public boolean deleteAttachments(List<Long> attachmentIds) {
        boolean success = true;
        for (Long attachmentId : attachmentIds) {
            if (!deleteAttachment(attachmentId)) {
                success = false;
            }
        }
        return success;
    }
    
    @Override
    public List<SalesOrderAttachmentDTO> getAttachmentsBySoId(Long soId) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getSoId, soId)
               .orderByDesc(SalesOrderAttachment::getUploadTime);
        
        List<SalesOrderAttachment> attachments = list(wrapper);
        return convertToDTOList(attachments);
    }
    
    @Override
    public List<SalesOrderAttachmentDTO> getValidAttachmentsBySoId(Long soId) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getSoId, soId)
               .eq(SalesOrderAttachment::getStatus, 1)
               .orderByDesc(SalesOrderAttachment::getUploadTime);
        
        List<SalesOrderAttachment> attachments = list(wrapper);
        return convertToDTOList(attachments);
    }
    
    @Override
    public IPage<SalesOrderAttachmentDTO> pageAttachments(Page<SalesOrderAttachment> page, Long soId, String attachmentType, String uploader) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(soId != null, SalesOrderAttachment::getSoId, soId)
               .eq(StringUtils.hasText(attachmentType), SalesOrderAttachment::getAttachmentType, attachmentType)
               .eq(StringUtils.hasText(uploader), SalesOrderAttachment::getUploader, uploader)
               .eq(SalesOrderAttachment::getStatus, 1)
               .orderByDesc(SalesOrderAttachment::getUploadTime);
        
        IPage<SalesOrderAttachment> attachmentPage = page(page, wrapper);
        
        // 转换为DTO
        IPage<SalesOrderAttachmentDTO> dtoPage = new Page<>();
        BeanUtils.copyProperties(attachmentPage, dtoPage);
        dtoPage.setRecords(convertToDTOList(attachmentPage.getRecords()));
        
        return dtoPage;
    }
    
    @Override
    public List<SalesOrderAttachmentDTO> getAttachmentsByType(String attachmentType) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getAttachmentType, attachmentType)
               .eq(SalesOrderAttachment::getStatus, 1)
               .orderByDesc(SalesOrderAttachment::getUploadTime);
        
        List<SalesOrderAttachment> attachments = list(wrapper);
        return convertToDTOList(attachments);
    }
    
    @Override
    public List<SalesOrderAttachmentDTO> getAttachmentsByUploader(String uploader) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getUploader, uploader)
               .eq(SalesOrderAttachment::getStatus, 1)
               .orderByDesc(SalesOrderAttachment::getUploadTime);
        
        List<SalesOrderAttachment> attachments = list(wrapper);
        return convertToDTOList(attachments);
    }
    
    @Override
    public Long countAttachmentsBySoId(Long soId) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getSoId, soId);
        return count(wrapper);
    }
    
    @Override
    public Long countValidAttachmentsBySoId(Long soId) {
        LambdaQueryWrapper<SalesOrderAttachment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesOrderAttachment::getSoId, soId)
               .eq(SalesOrderAttachment::getStatus, 1);
        return count(wrapper);
    }
    
    @Override
    public byte[] previewAttachment(Long attachmentId) throws IOException {
        SalesOrderAttachment attachment = getById(attachmentId);
        if (attachment == null) {
            throw new RuntimeException("附件不存在");
        }
        
        File file = new File(attachment.getFilePath());
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }
        
        try (FileInputStream fis = new FileInputStream(file);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                baos.write(buffer, 0, length);
            }
            return baos.toByteArray();
        }
    }
    
    @Override
    public SalesOrderAttachmentDTO getAttachmentInfo(Long attachmentId) {
        SalesOrderAttachment attachment = getById(attachmentId);
        return attachment != null ? convertToDTO(attachment) : null;
    }
    
    @Override
    public boolean updateAttachmentDescription(Long attachmentId, String description) {
        SalesOrderAttachment attachment = getById(attachmentId);
        if (attachment == null) {
            return false;
        }
        
        attachment.setDescription(description);
        attachment.setUpdatedAt(new Date());
        return updateById(attachment);
    }
    
    @Override
    public boolean checkAttachmentExists(Long attachmentId) {
        return getById(attachmentId) != null;
    }
    
    @Override
    public boolean isAllowedFileType(String fileName) {
        String extension = getFileExtension(fileName);
        return ALLOWED_EXTENSIONS.contains(extension.toLowerCase());
    }
    
    @Override
    public List<String> getAllowedFileTypes() {
        return new ArrayList<>(ALLOWED_EXTENSIONS);
    }
    
    @Override
    public long getMaxFileSize() {
        return maxFileSize;
    }
    
    // 私有辅助方法
    
    private void validateFile(MultipartFile file) {
        System.out.println("=== 文件验证开始 ===");
        System.out.println("文件对象: " + (file != null ? "非空" : "null"));
        
        if (file == null || file.isEmpty()) {
            System.out.println("文件验证失败：文件为空或null");
            throw new RuntimeException("文件不能为空");
        }
        
        System.out.println("文件大小: " + file.getSize() + " bytes");
        System.out.println("最大允许大小: " + maxFileSize + " bytes");
        
        if (file.getSize() > maxFileSize) {
            System.out.println("文件验证失败：文件大小超过限制");
            throw new RuntimeException("文件大小超过限制：" + (maxFileSize / 1024 / 1024) + "MB");
        }
        
        String originalFilename = file.getOriginalFilename();
        System.out.println("原始文件名: " + originalFilename);
        
        if (!isAllowedFileType(originalFilename)) {
            System.out.println("文件验证失败：不支持的文件类型");
            throw new RuntimeException("不支持的文件类型");
        }
        
        System.out.println("文件验证通过");
        System.out.println("=== 文件验证结束 ===");
    }
    
    private String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }
    
    private String generateFileName(String originalFilename) {
        String extension = getFileExtension(originalFilename);
        return UUID.randomUUID().toString() + "." + extension;
    }
    
    private String determineAttachmentType(String extension) {
        // 根据文件扩展名确定附件类型
        extension = extension.toLowerCase();
        if (Arrays.asList("pdf", "doc", "docx").contains(extension)) {
            return "CONTRACT";
        } else if (Arrays.asList("jpg", "jpeg", "png", "gif").contains(extension)) {
            return "INVOICE";
        } else if (Arrays.asList("xls", "xlsx").contains(extension)) {
            return "QUALITY";
        } else {
            return "OTHER";
        }
    }
    
    private SalesOrderAttachmentDTO convertToDTO(SalesOrderAttachment attachment) {
        if (attachment == null) {
            return null;
        }
        
        SalesOrderAttachmentDTO dto = new SalesOrderAttachmentDTO();
        BeanUtils.copyProperties(attachment, dto);
        return dto;
    }
    
    private List<SalesOrderAttachmentDTO> convertToDTOList(List<SalesOrderAttachment> attachments) {
        if (attachments == null || attachments.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<SalesOrderAttachmentDTO> dtoList = new ArrayList<>();
        for (SalesOrderAttachment attachment : attachments) {
            dtoList.add(convertToDTO(attachment));
        }
        return dtoList;
    }
}
